package com.xyh.transaction.service.imp;

import com.github.pagehelper.PageInfo;
import com.xyh.transaction.common.Current;
import com.xyh.transaction.entity.Menu;
import com.xyh.transaction.entity.Role;
import com.xyh.transaction.entity.dto.button.ButtonDto;
import com.xyh.transaction.entity.dto.menu.MenuEditOrAddDto;
import com.xyh.transaction.entity.dto.menu.MenuSearchDto;
import com.xyh.transaction.entity.dto.user.ArrDto;
import com.xyh.transaction.entity.vo.MenuOptionsVO;
import com.xyh.transaction.entity.vo.MetaPropsVO;
import com.xyh.transaction.exception.DeleteException;
import com.xyh.transaction.exception.InsertException;
import com.xyh.transaction.exception.UpdateException;
import com.xyh.transaction.mapper.ButtonMapper;
import com.xyh.transaction.mapper.RoleMapper;
import com.xyh.transaction.mapper.MenuMapper;
import com.xyh.transaction.mapper.UserMapper;
import com.xyh.transaction.service.MenuService;
import com.xyh.transaction.utils.MappingUtil;
import com.xyh.transaction.utils.PageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl implements MenuService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ButtonMapper buttonMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Override
    public Set<MenuOptionsVO> getAuthMenuList() {
        Integer userId = Current.getCurrentUser().getUser().getId();
        LinkedHashSet<MenuOptionsVO> authMenuList = new LinkedHashSet<>();
        Set<Role> roleList = roleMapper.findRoleByUserId(userId);

        HashSet<Integer> menuIdSet = new HashSet<>();
        for (Role role : roleList) {
            List<Integer> routeIdList = roleMapper.findMenuIdListByRoleId(role.getId());
            menuIdSet.addAll(routeIdList);
        }


        authMenuList.addAll(buildMenus(menuMapper.findAllByMenuIds(menuIdSet),null));

//        for (Integer menuId : menuIdSet) {
//            List<Menu> menuList = menuMapper.findAllByMenuId(menuId);
//            for (Menu menu : menuList) {
//                MenuOptionsVO menuOptionsVO = buildMenuOptions(menu);
//                authMenuList.add(menuOptionsVO);
//            }
//        }

        return authMenuList;
    }

    public LinkedHashSet<MenuOptionsVO> buildMenus(List<Menu> menuList, Integer parentId) {
        LinkedHashSet<MenuOptionsVO> authMenuList = new LinkedHashSet<>();
        for (Menu menu : menuList) {
            MenuOptionsVO menuOptionsVO = MappingUtil.mapObject(menu, MenuOptionsVO.class);
            MetaPropsVO metaPropsVO = MappingUtil.mapObject(menu, MetaPropsVO.class);
            menuOptionsVO.setMeta(metaPropsVO);

            // 获取当前菜单的子菜单
            LinkedHashSet<MenuOptionsVO> childOptions;
            if (Objects.equals(menu.getParentId(), parentId)) {
                // 递归处理子菜单，并传入当前子菜单列表进行处理
                childOptions = buildMenus(menuList, menu.getId());
                menuOptionsVO.setChildren(new ArrayList<>(childOptions));
                authMenuList.add(menuOptionsVO);
            }
        }

        return authMenuList;
    }

    public List<Menu> getChildren(List<Menu> routeList,int id) {
        return routeList.stream().filter(m -> m.getParentId() == id).collect(Collectors.toList());
    }

    @Override
    public PageInfo<MenuOptionsVO> getMenuList(MenuSearchDto menuSearchDto) {
        Menu menu = MappingUtil.mapObject(menuSearchDto, Menu.class);
        List<Menu> menuList = menuMapper.findAll(menu);

        List<MenuOptionsVO> menuOptionsVOList = buildMenuOptions(menuList, null);

        // 假分页处理
        return PageUtil.paginateList(menuOptionsVOList,menuSearchDto.getPageNum(),menuSearchDto.getPageSize());
    }

    @Override
    @Transactional
    public void updateMenu(MenuEditOrAddDto menuEditOrAddDto) {
        Menu menu = MappingUtil.mapObject(menuEditOrAddDto, Menu.class);

        // 先删除按钮权限列表，再添加
        int menuId = menu.getId();
        buttonMapper.deleteByMenuId(menuId);
        if (!menuEditOrAddDto.getAuthButtons().isEmpty()){
            buttonMapper.insertButtonAuths(menuEditOrAddDto.getAuthButtons(), menuId);
        }

        Integer uRows = menuMapper.updateById(menu);

        if (uRows <= 0) {
            throw new UpdateException("修改菜单数据失败，未更新任何记录。");
        }
    }

    @Override
    @Transactional
    public void addMenu(MenuEditOrAddDto menuEditOrAddDto) {

        Menu menu = MappingUtil.mapObject(menuEditOrAddDto, Menu.class);

        Collection<Integer> authButtons = menuEditOrAddDto.getAuthButtons();
        if (!authButtons.isEmpty()){
            Integer iRows1 = buttonMapper.insertButtonAuths(authButtons, menu.getId());

            if (iRows1 <= 0 ) {
                throw new InsertException("菜单添加按钮权限失败，未插入任何数据！");
            }
        }

        if (menu.getIsAffix() == null){
            menu.setIsAffix(false);
        }
        if (menu.getIsFull() == null){
            menu.setIsFull(false);
        }
        if (menu.getIsHide() == null){
            menu.setIsHide(false);
        }
        if (menu.getIsKeepAlive() == null){
            menu.setIsKeepAlive(false);
        }
        Integer iRows2 = menuMapper.insert(menu);

        if (iRows2 <= 0) {
            throw new InsertException("新增菜单数据失败，未插入任何记录。");
        }

    }

    @Override
    public List<MenuOptionsVO> getAllMenu() {
        List<Menu> menuList = menuMapper.findAll(new Menu());

        return menuList.stream().map(menu -> {
            MenuOptionsVO menuOptionsVO = MappingUtil.mapObject(menu, MenuOptionsVO.class);
            MetaPropsVO metaPropsVO = MappingUtil.mapObject(menu, MetaPropsVO.class);
            menuOptionsVO.setMeta(metaPropsVO);
            return menuOptionsVO;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void deleteMenu(ArrDto arrDto) {
        Integer[] ids = arrDto.getId();

        Integer i = menuMapper.deleteById(ids);

        if (i <= 0){
            throw new DeleteException("删除菜单数据失败，未删除任何数据");
        }

        // 递归删除子集菜单路由
        recursiveDelete(ids);

    }

    private void recursiveDelete(Integer[] ids) {
        Arrays.stream(ids).forEach(id -> {
            List<Menu> childrens = menuMapper.findChildrenByParentId(id);
            if (!childrens.isEmpty()) {
                Integer[] idArr = childrens.stream().map(Menu::getId).toArray(Integer[]::new);
                if (idArr.length > 0) {
                    Integer i = menuMapper.deleteById(idArr);
                    if (i <= 0){
                        throw new DeleteException("删除菜单数据失败，未删除任何数据");
                    }
                    recursiveDelete(idArr);
                }
            }
        });
    }

    private MenuOptionsVO buildMenuOptions(Menu menu) {
        MenuOptionsVO menuOptionsVO = MappingUtil.mapObject(menu, MenuOptionsVO.class);
        MetaPropsVO metaPropsVO = MappingUtil.mapObject(menu, MetaPropsVO.class);
        menuOptionsVO.setMeta(metaPropsVO);

        List<Menu> children = menuMapper.findChildrenByParentId(menu.getId());
        if (!children.isEmpty()) {
            LinkedHashSet<MenuOptionsVO> childrenList = new LinkedHashSet<>();
            for (Menu child : children) {
                MenuOptionsVO childMenuOptions = buildMenuOptions(child);
                childrenList.add(childMenuOptions);
            }
            menuOptionsVO.setChildren(childrenList);
        }

        return menuOptionsVO;
    }

    private List<MenuOptionsVO> buildMenuOptions(List<Menu> menuList, Integer parentId) {
        List<MenuOptionsVO> authMenuList = new ArrayList<>();

        List<Menu> childMenus = menuList.stream()
                .filter(m -> Objects.equals(m.getParentId(), parentId))
                .collect(Collectors.toList());

        for (Menu childMenu : childMenus) {
            MenuOptionsVO menuOptionsVO = MappingUtil.mapObject(childMenu, MenuOptionsVO.class);
            MetaPropsVO metaPropsVO = MappingUtil.mapObject(childMenu, MetaPropsVO.class);
            menuOptionsVO.setMeta(metaPropsVO);
            menuOptionsVO.setAuthButtons(buttonMapper.findButtonAuthByMenuId(childMenu.getId()).stream()
                    .map(ButtonDto::getButtonId)
                    .collect(Collectors.toSet()));

            List<MenuOptionsVO> children = buildMenuOptions(menuList, childMenu.getId());
            if (!children.isEmpty()) {
                menuOptionsVO.setChildren(children);
//                menuOptionsVO.setChildren(children.stream()
//                        .sorted(Comparator.comparingInt(MenuOptionsVO::getId))
//                        .collect(Collectors.toCollection(LinkedHashSet::new)));
            }

            authMenuList.add(menuOptionsVO);
        }

        return authMenuList;
    }
}
